/**
 * 
 */
package org.rk.core.jdbc.dao;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import org.rk.core.common.bean.PageData;
import org.rk.core.common.bean.QueryData;
import org.rk.core.common.util.RKAlert;
import org.rk.core.common.util.RkObjectUtil;
import org.rk.core.jdbc.dao.util.Condition;
import org.rk.core.jdbc.dao.util.ParamMap;
import org.rk.core.jdbc.dao.util.SQLUtils;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;
import org.springframework.transaction.annotation.Transactional;

/**
 * @author cavion 2015/4/30
 * @param <T>
 */
public abstract class DBDao<T> implements IDBDao<T> {

	private JdbcTemplate jdbcTemplate;
	private NamedParameterJdbcTemplate simpleJdbc;

	/**
	 * 
	 * @描述：保存实体
	 * @param obj
	 * @return false/ture 2015/4/30 上午10:54:58
	 * @author cavion
	 */
	@Override
	public boolean saveModel(T bean) {
		String sql = SQLUtils.buildInsertSql(bean.getClass());
		SqlParameterSource sps = new BeanPropertySqlParameterSource(bean);
		int result = this.simpleJdbc.update(sql, sps);
		return result > 0 ? true : false;
	}
	
	@Override
	public Long saveModelToId(T bean){
		Long id=null;
		KeyHolder keyHolde=new GeneratedKeyHolder();
		String sql = SQLUtils.buildInsertSql(bean.getClass());
		SqlParameterSource sps = new BeanPropertySqlParameterSource(bean);
		int result=this.simpleJdbc.update(sql, sps, keyHolde);
		if(result>0){
			id=keyHolde.getKey().longValue();
		}
		return id;
	}

	/**
	 * @描述：删除
	 * @param obj
	 * @return 2015/4/30 10:57:33
	 * @author cavion
	 */
	@Override
	public boolean deleteModel(T bean) {
		String sql = SQLUtils.buildDeleteSqlByPk(bean.getClass());
		SqlParameterSource sps = new BeanPropertySqlParameterSource(bean);
		int result = this.simpleJdbc.update(sql, sps);
		return result > 0 ? true : false;
	}
	/**
	 * @描述：根据uid删除
	 * @param obj
	 * @return 2015/4/30 10:57:33
	 * @author cavion
	 */
	@Override
	public boolean deleteModelByUnique(T bean) {
		String sql = SQLUtils.buildDeleteSqlByUnique(bean.getClass());
		SqlParameterSource sps = new BeanPropertySqlParameterSource(bean);
		int result = this.simpleJdbc.update(sql, sps);
		return result > 0 ? true : false;
	}
	@Override
	public Integer deleteByParamMap(Class<T> cs, List<ParamMap> paramMapList) {
		Map<String, Object> params = ParamMap.genParams(paramMapList);
		String sql="";
		try {
			sql = SQLUtils.buildDeleteSqlByMapParams(cs, params.keySet());
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			RKAlert.Error("sql构建异常");
		}
		SqlParameterSource sps = new MapSqlParameterSource(params);
		return this.simpleJdbc.update(sql, sps);
	}
	/**
	 * 
	 * 2016年9月10日 上午11:00:43
	 * 
	 * @author:cavion
	 * @描述：根据bean的部分字段的条件来删除bean
	 * @param bean
	 * @param fileds
	 * @return
	 * @throws Exception
	 */

	@Override
	public Integer deleteWithColumn(T bean, String[] fileds) {
		String sql="";
		try {
			sql = SQLUtils.buildDeleteSqlByColumns(bean.getClass(), fileds);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			RKAlert.Error("sql构建异常");
		}
		SqlParameterSource sps = new BeanPropertySqlParameterSource(bean);
		return this.simpleJdbc.update(sql, sps);
	}

	/**
	 * 
	 * @描述：更新
	 * @param obj
	 * @return 2015/4/30 10:58:34
	 * @author cavion
	 */
	@Override
	@Transactional
	public boolean updateModel(T bean) {
		String sql = SQLUtils.buildUpdateSqlByPk(bean);
		SqlParameterSource sps = new BeanPropertySqlParameterSource(bean);
		return this.simpleJdbc.update(sql, sps) > 0 ? true : false;
	}
	/**
	 * 
	 * @描述：更新
	 * @param obj
	 * @return 2015/4/30 10:58:34
	 * @author cavion
	 */
	@Override
	@Transactional
	public boolean updateModelByUnique(T bean) {
		String sql = SQLUtils.buildUpdateSqlByUnique(bean);
		SqlParameterSource sps = new BeanPropertySqlParameterSource(bean);
		return this.simpleJdbc.update(sql, sps) > 0 ? true : false;
	}
	
	@Override
	@Transactional
	public boolean updateWithColumn(T bean, String[] fileds){
		String sql="";
		try {
			sql = SQLUtils.buildUpdateSqlByColumns(bean.getClass(), fileds);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			RKAlert.Error("sql构建异常");
		}
		SqlParameterSource sps = new BeanPropertySqlParameterSource(bean);
		return this.jdbcTemplate.update(sql, sps) > 0 ? true : false;
	}

	/**
	 * 
	 * 2016年9月10日 上午11:08:05
	 * 
	 * @author:cavion
	 * @描述：自动分页/不分页查询返回list
	 * @param cs
	 * @param paramMap
	 * @return
	 * @throws Exception
	 */
	@Override
	public PageData queryToPage(Class<T> cs, List<ParamMap> paramMapList, PageData page){
		paramMapList = ParamMap.addPageToParamMap(paramMapList, page);
		String sql =Condition.buildConditionSql(cs, paramMapList,SQLUtils.buildSelectSql(cs));
		List<Map<String, Object>> list = this.simpleJdbc.queryForList(sql, ParamMap.genParams(paramMapList));
		
		page.setRecordsTotal(queryCount(cs, paramMapList));
		page.setData(list);
		return page;
	}

	public Long queryCount(Class<T> cs, List<ParamMap> paramMapList){
		String countSql =Condition.buildConditionSqlNoLimit(cs,paramMapList,SQLUtils.buildSelectCountSql(cs));
		Map<String, Object> result=this.simpleJdbc.queryForMap(countSql, ParamMap.genParams(paramMapList));
		Object countNum=result.get("countNum");
		return (Long) countNum;
	}
	public Long queryCountBySql(String sql, List<ParamMap> paramMapList){
		String countSql ="select count(1) as countNum from ("+sql+") countTmp";
		Map<String, Object> result=this.simpleJdbc.queryForMap(countSql, ParamMap.genParams(paramMapList));
		Object countNum=result.get("countNum");
		return (Long) countNum;
	}
	@SuppressWarnings("unchecked")
	@Override
	public List<T> queryForList(Class<T> cs, List<ParamMap> paramMapList){
		String sql = SQLUtils.buildSelectSql(cs) + Condition.buildWhereSql(cs, paramMapList);

		List<T> listT = new ArrayList<T>();
		List<Map<String, Object>> list = this.simpleJdbc.queryForList(sql, ParamMap.genParams(paramMapList));
		for (Map<String, Object> map : list) {
			T t = (T) SQLUtils.coverMapToBean(map, cs);
			listT.add(t);
		}
		return listT;
	}

	@SuppressWarnings("unchecked")
	@Override
	public T queryForEntity(Class<T> cs, List<ParamMap> paramMapList){
		String sql = SQLUtils.buildSelectSql(cs) + Condition.buildWhereSql(cs, paramMapList);
		List<Map<String, Object>> list = this.simpleJdbc.queryForList(sql, ParamMap.genParams(paramMapList));

		if (RkObjectUtil.isEmpty(list) || list.size() < 1) {
			return null;
		} else if (list.size() > 1) {
			RKAlert.Error("查询结果多余1条");
			Map<String, Object> map = (Map<String, Object>) list.get(0);
			return (T) SQLUtils.coverMapToBean(map, cs);
		} else {
			Map<String, Object> map = (Map<String, Object>) list.get(0);
			return (T) SQLUtils.coverMapToBean(map, cs);
		}
	}

	@Override
	public QueryData queryBySql(String sql,List<ParamMap> paramMapList){
		List<Map<String, Object>> result=this.simpleJdbc.queryForList(sql, ParamMap.genParams(paramMapList));
		QueryData qds=new QueryData();
		qds.setQueryBeanList(result);
		return qds;
	}
	@Override
	public PageData queryBySqlToPage(String sql,List<ParamMap> paramMapList,PageData page){
		Long countNum=queryCountBySql(sql, paramMapList);
		sql=Condition.buildLimiSql(sql,paramMapList);
		List<Map<String, Object>> result=this.simpleJdbc.queryForList(sql, ParamMap.genParams(paramMapList));
		page.setData(result);
		page.setRecordsTotal(countNum);
		return page;
	}
	
	@Override
	public Long queryMaxId(Class<T> cs){
		String tableName=SQLUtils.loadTableName(cs);
		QueryData qd=queryBySql("select max(id) as id from "+tableName, Collections.emptyList());
		if(RkObjectUtil.isEmpty(qd)){
			return 1L;
		}
		Map<String,Object> result=qd.get(0);
		Long maxId=(Long) result.get("id");
		return maxId;
	}
	@Override
	public void executeBySql(String sql){
		jdbcTemplate.execute(sql);
	}
	
	public int[] executeBySql(String sql,List<Object[]> batchArgs){
		int[] result=jdbcTemplate.batchUpdate(sql, batchArgs);//jdbcTemplate.getFetchSize();
		return result;
	}
	
	public JdbcTemplate getJdbcTemplate() {
		return jdbcTemplate;
	}

	public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
		this.jdbcTemplate = jdbcTemplate;
		this.simpleJdbc = new NamedParameterJdbcTemplate(jdbcTemplate.getDataSource());
	}

}
